package com.higgins.client.generic.components;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTMLTable;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.HTMLTable.Cell;
import com.higgins.client.dataModel.CoveringLetterDTO;

public class GenericTable extends FlexTable	{
	protected GenericColumns genericColumns = null;
    private String dateFormat = "dd MMM yyyy";
	
	public GenericTable(GenericColumns genericColumns)	{
		super();
		this.genericColumns = genericColumns;
		initialise();
		initialiseTable(genericColumns);
		addHandler();
	}
	public void setColumns(GenericColumns genericColumns)	{
		this.genericColumns = genericColumns;
	}
	public GenericColumns getColumns()	{
		return genericColumns;
	}
	protected void initialise()	{
		this.setCellPadding(1);
		this.setCellSpacing(0);
		this.setWidth("" + genericColumns.getWidth() + "px");
		
		RowFormatter rf = this.getRowFormatter();
		rf.setStyleName(0, "FlexTable-HeaderRow");

		for (GenericColumn column:genericColumns.getColumns())	{
			getColumnFormatter().setWidth(column.getIndex(), "" + column.getWidth() + "px"); 
			if (column.getTitle().toUpperCase().equals("ID"))	{
				addIDHeader();
			} else	{
				addHeader(column);
			}
		}
	}	
	protected void initialiseTable(GenericColumns columns)	{
		setColumns(columns);
	}
	public void refresh()	{
		clearOutTable();
		initialise();
		initialiseTable(genericColumns);
		retrieveDTOs();
	}

	private void addIDHeader()	{
		this.getCellFormatter().addStyleName(0, 0,"FlexTable-checkBoxCell");
		addCheckBox(0,0, false, null);
	}
	
	private void addHeader(GenericColumn column)	{
		this.setText(0, column.getIndex(), column.getTitle());
		this.getCellFormatter().addStyleName(0, column.getIndex(), "FlexTable-normCell");
	}

	public void addRow(int rowCount, List<Object> row)	{
		ensureRowAvailable(rowCount);
		for (GenericColumn column:genericColumns.getColumns())	{
//			Object obj = row.get(column.getIndex());
			if (column.getTitle().toUpperCase().equals("ID"))	{
				addCheckBox(rowCount+1, 0, false, row.get(column.getIndex())!=null?Long.parseLong(row.get(column.getIndex()).toString()):null);
			} else if (column.getType().equals(String.class))	{
				addString(rowCount+1, column.getIndex(), row.get(column.getIndex())!=null?row.get(column.getIndex()).toString():"");
			} else if (column.getType().equals(Double.class))	{
				addDouble(rowCount+1, column.getIndex(), row.get(column.getIndex())!=null? (Double) row.get(column.getIndex()): (Double) 0.0);
			} else if (column.getType().equals(Integer.class))	{
				addInteger(rowCount+1, column.getIndex(), row.get(column.getIndex())!=null? (Integer) row.get(column.getIndex()): (Integer) 0);
			} else if (column.getType().equals(Date.class))	{
				addDate(rowCount+1, column.getIndex(), row.get(column.getIndex())!=null? (Date) row.get(column.getIndex()): (Date) new Date());
			} else if (column.getType().equals(Boolean.class))	{
				addBoolean(rowCount+1, column.getIndex(), row.get(column.getIndex())!=null? (Boolean) row.get(column.getIndex()): (Boolean) new Boolean(false));
			} else {
				addObject(rowCount+1, column.getIndex(), row.get(column.getIndex())!=null? (Object) row.get(column.getIndex()): (Object) new Object());
			}

		}		
	}

	public void clearTable()	{
		int rows = getRowCount();
		for (int row = 1; row < rows; row++)
			this.removeRow(getRowCount()-1);
	}
	
	public void ensureRowAvailable(int row)	{
		int rowCount = this.getRowCount();
		if (rowCount <= (row + 1))
			this.insertRow(rowCount);
	}
	public void addString(int row, int column, String text)	{
		ensureRowAvailable(row);
		this.setText(row,column,restrictTextLength(text, 40));
		getCellFormatter().addStyleName(row, column, "FlexTable-normCell");
	}
	private String restrictTextLength(String text, int length)	{
//		if (text.length()>40)	{
//			return text.substring(0, 40);
//		} else {
			return text;
//		}
	}
	public void addDouble(int row, int column, Double number)	{
		ensureRowAvailable(row);
		this.setText(row, column,convertDoubleToString(number));
 		getCellFormatter().addStyleName(row, column, "FlexTable-normCell");
	}
	public void addInteger(int row, int column, Integer number)	{
		ensureRowAvailable(row);
		this.setText(row, column,convertIntegerToString(number));
 		getCellFormatter().addStyleName(row, column, "FlexTable-normCell");
	}
	public void addDate(int row, int column, Date date)	{
		ensureRowAvailable(row);
		this.setText(row, column,convertDateToString(date));
 		getCellFormatter().addStyleName(row, column, "FlexTable-normCell");
	}
	public void addBoolean(int row, int column, Boolean booleanField)	{
		ensureRowAvailable(row);
		CheckBox booleanCheckBox = new CheckBox();
		booleanCheckBox.setValue(booleanField);
		setWidget(row, column, booleanCheckBox);
 		getCellFormatter().addStyleName(row, column, "FlexTable-normCell");
 		booleanCheckBox.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				Cell cell = getCellForEvent(event);
				final int row = cell.getRowIndex();
				final int column = cell.getCellIndex();
				setRowUpdateTag(row);
				updateItemCell(row);
			}
		});
	}
	protected void addObject(int row, int column, Object object)	{
	}
	protected String convertDoubleToString(Double inValue){
		String stringValue = inValue.toString();
		int positionOfDot = stringValue.indexOf(".");
		int lengthOfNumberText = stringValue.length();
		if ((lengthOfNumberText - positionOfDot) > 4)
			lengthOfNumberText = positionOfDot+4;
		if (positionOfDot>0)
			stringValue = stringValue.substring(0, lengthOfNumberText);
		return stringValue;
	}	
	protected String convertIntegerToString(Integer inValue){
		return inValue.toString();
	}	
	
	public void insertNewRow()	{
		List<Object> newRow = new ArrayList<Object>();
		for (GenericColumn column:genericColumns.getColumns())	{
			if (column.getTitle().toLowerCase().equals("id"))	{
				newRow.add(null);
			} else if (column.getType().equals(String.class))	{
				newRow.add("");
			} else if (column.getType().equals(Integer.class))	{
				newRow.add(1);
			} else if (column.getType().equals(Double.class))	{
				newRow.add(0.0);
			} else if (column.getType().equals(Date.class))	{
				newRow.add(new Date());
			} else if (column.getType().equals(Boolean.class))	{
				newRow.add(new Boolean(false));
			} else	{
				newRow.add("");
			}
		}
		addRow(this.getRowCount(), newRow);
	}
	
	private void makeTableEditable(ClickEvent event)	{
		Cell cell = getCellForEvent(event);
		final int row = cell.getRowIndex();
		final int column = cell.getCellIndex();
		makeTableEditable(row, column);
	}
	protected void makeTableEditable(final int row, final int column)	{
		GenericColumn genericColumn = genericColumns.getColumns().get(column);
		if (genericColumn.getEditable() && (
				genericColumn.getType().equals(String.class)	||
				genericColumn.getType().equals(Double.class)	||
				genericColumn.getType().equals(Date.class)))		{
			
			makeGenericCellEditable(row, column);
		} else if (genericColumn.getType().equals(Boolean.class))	{
			//
		} else if (genericColumn.getEditable()) {
			makeCellEditable(row, column);
		}				
	}
	
	protected void makeGenericCellEditable(final int row, final int column)	{
		Widget widget = getWidget(row, column);
		if (widget!=null && widget.getClass().equals(TextBox.class))	{
			return;
		}
		final TextBox textBox = new TextBox();
		textBox.setText(getText(row, column));
		textBox.setFocus(true);
		textBox.setCursorPos(0);
		setWidget(row, column, textBox);
		textBox.addKeyDownHandler(new KeyDownHandler() {

			@Override
			public void onKeyDown(KeyDownEvent event) {
				// TODO Auto-generated method stub
				int code = event.getNativeKeyCode();
				if (KeyCodes.KEY_ENTER == code || KeyCodes.KEY_TAB == code)	{
					setWidget(row, column, new Label(textBox.getText()));
					setRowUpdateTag(row);
					updateItemCell(row);
					if (genericColumns.getColumns().size() > (column + 1))	{
						makeTableEditable(row, (column+1));
					}
				}
				if (KeyCodes.KEY_ESCAPE == code)	{
					setWidget(row, column, new Label(textBox.getText()));
				}
			}
		});
		textBox.setFocus(true);
	}
	
	public void updateItemCell(int row)	{
			// UPDATE THE DATABASE WITH THE NEW VALUES
	}
	private void addCheckBox(int row, int column, Boolean apply, Long id)	{
		CheckBox checkBox = new CheckBox();
		checkBox.setName(id!=null?id.toString():"null");

		setWidget(row, column, checkBox);
		checkBox.setValue(apply!=null?apply:false);
		getCellFormatter().addStyleName(row, column, "FlexTable-checkBoxCell");
		addCheckBoxListener(checkBox);
	}
	protected void addCheckBoxListener(CheckBox checkBox)	{
		checkBox.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {
				checkBoxClick(event);
			}
		});
	}
	
	protected Long getId(Integer row)	{
		try	{
			CheckBox checkBox = (CheckBox)getWidget(row, 0);
			String name = checkBox.getName();
			return Long.parseLong(name);
		} catch (Exception e)	{
			return null;
		}
	}
	protected Integer getRow(Long id)	{
		int rows = getRowCount();
		for (int row = 1; row < rows; row++)	{
			Long tableRowId = getId(row);
			if (id.equals(tableRowId))	{
				return row;
			}
		}
		return null;
	}
	
	protected Double getDouble(int row, int column)	{
		try	{
			return Double.parseDouble(getText(row, column));		
		} catch (Exception e)	{
			return 0.0;
		}
	}
	protected Integer getInteger(int row, int column)	{
		try	{
			return Integer.parseInt(getText(row, column));		
		} catch (Exception e)	{
			return 1;
		}
	}
	protected Date getDate(int row, int column)	{
		try	{
//			DateTimeFormat format = DateTimeFormat.getFullDateTimeFormat();
//			.format(today);
//			DateFormat format = DateFormat.getDateTimeInstance();
//			return format.parse(getText(row, column));
			String string = getText(row, column);
			Long longDate = Date.parse(string);
			Date newDate = new Date(longDate);
			return newDate;
		} catch (Exception e)	{
			return null;
		}
	}
	protected Boolean getBoolean(int row, int column)	{
		try	{
			CheckBox booleanCheckBox = (CheckBox)getWidget(row, column);
			return booleanCheckBox.getValue();
		} catch (Exception e)	{
			return false;
		}
	}

	protected void loadData(List<List<Object>> dataMatrix)	{
		int row = 0;
		for (List<Object> rowData:dataMatrix)		{
			addRow(row++, rowData);
		}
	}

	
	protected void addHandler()	{
		addClickHandler(new ClickHandler()	{

			@Override
			public void onClick(ClickEvent event) {
				Cell cell = getCellForEvent(event);
				final int row = cell.getRowIndex();
				final int column = cell.getCellIndex();
				if (row == 0 && column > 0)	{
					insertNewRow();
				} else {
					if (genericColumns.getColumn(column).getEditable())	{
						makeTableEditable(event);
					}
				}
			}
		});
	}

	
	protected void setRowIdAfterUpdate(String id)	{
		int count = 0;
		int updateRow = 0;
		int rowCount = getRowCount();
		for (int row = 0; row < (rowCount); row++)	{
			CheckBox checkBox = null;
			try	{
				checkBox = (CheckBox)getWidget(row, 0);
			} catch (Exception e)	{
			}
			String name = checkBox!=null?checkBox.getName():"";
			if (name.toLowerCase().equals("update"))	{
				count++;
				updateRow = row;
			}
		}
		if (count > 1)	{
			refresh();
		} else if (count > 0)	{
			CheckBox checkBox = (CheckBox)getWidget(updateRow, 0);
			checkBox.setName(id);
		}
	}
	protected void setRowUpdateTag(int row)	{
		CheckBox checkBox = (CheckBox)getWidget(row, 0);
		String name = checkBox.getName();
		if (name==null || name.equals("null"))	{
			checkBox.setName("update");
		}
	}

	protected void retrieveDTOs()	{
	}
	protected void makeCellEditable(final int row, final int column)	{
	}
	protected void clearOutTable()	{
		clear();
		int count = getRowCount(); 
		while (count > 0) { 
			removeRow(0); 
			count = getRowCount(); 
		} 		
	}
	protected void setCheckBox(int row)	{
		CheckBox checkBox = (CheckBox)getWidget(row, 0);
		checkBox.setValue(true);
	}

	protected void checkBoxClick(ClickEvent event)	{
		Cell cell = getCellForEvent(event);
		final int row = cell.getRowIndex();
		final int column = cell.getCellIndex();
		CheckBox checkBox = (CheckBox)getWidget(row, column);
		Long id = getId(row);
		if (checkBox.getValue())	{
			checkBoxSet(id);
		} else {
			checkBoxCleared(id);
		}
	}
	protected void setCheckBoxes(List<Long> ids)	{
		int rows = getRowCount();
		for (int row = 1; row < rows; row++)	{
			Long recipientId = getId(row);
			if (recipientId!=null && ids.contains(recipientId))	{
				setCheckBox(row);
			}
		}
	}
	protected void checkBoxSet(Long id)	{
		
	}
	protected void checkBoxCleared(Long id)	{
		
	}
	protected String convertDateToString(Date inValue){
	    DateTimeFormat format = DateTimeFormat.getFormat(dateFormat);
	    return format.format(inValue);
	}   

}
